<?php
namespace Fendx\Tools;

class OpenSSL {
    private $key = '';

    public function __construct(string $key) {
        $this->key = $key;
    }


    public static function Factory(string $key): OpenSSL {
        static $_obj = [];
        //是否需要重新连接
        if (!isset($_obj[$key])) {
            $_obj[$key] = new self($key);
        }
        return $_obj[$key];
    }

    public function encrypt(string $plaintext): string {
        $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($plaintext, $cipher, $this->key, $options=OPENSSL_RAW_DATA, $iv);
        $hmac = hash_hmac('sha256', $ciphertext_raw, $this->key, $as_binary=true);
        $ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
        return $ciphertext;
    }

    public function decrypt(string $ciphertext): string {
        $c = base64_decode($ciphertext);
        $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
        $iv = substr($c, 0, $ivlen);
        $hmac = substr($c, $ivlen, $sha2len=32);
        $ciphertext_raw = substr($c, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $this->key, $options=OPENSSL_RAW_DATA, $iv);
        $calcmac = hash_hmac('sha256', $ciphertext_raw, $this->key, $as_binary=true);
        if (!hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
        {
            throw new DataValidationException('decrypt error');
        }
        return $original_plaintext;
    }
}
